﻿using System;
using System.Collections.Generic;
using System.Text;

namespace JustMathCore.FilePool
{
    class ThreadWrite
    {
        public Dictionary<byte, FileItem> items = new Dictionary<byte, FileItem>();
        System.Collections.Concurrent.ConcurrentQueue<byte[]> msg = new System.Collections.Concurrent.ConcurrentQueue<byte[]>();
        public void Queue(byte[] byteline)
        {
            msg.Enqueue(byteline);
        }
        public int QueueSize
        {
            get
            {
                return msg.Count;
            }
        }
        public void Apply()
        {
            foreach (var item in items.Values)
            {
                item.Apply();
            }
        }
        public void Start()
        {
            worker = new System.Threading.Thread(() =>
             {
                 while (!exit)
                 {
                     if (msg.TryDequeue(out byte[] line))
                     {
                         items[line[0]].WriteLine(line);
                     }
                     else
                     {
                         System.Threading.Thread.Sleep(100);
                     }

                 }
             });
            worker.IsBackground = true;
            worker.Start();

        }
        System.Threading.Thread worker;
        bool exit = false;
        public void Stop()
        {
            exit = true;
        }
    }

    public class ThreadWriteMgr
    {
        static ThreadWrite[] threads;
        public static void Start(LinePool pool, int threadcount)
        {
            threads = new ThreadWrite[threadcount];
            for (var i = 0; i < threadcount; i++)
            {
                threads[i] = new ThreadWrite();
                threads[i].Start();
            }
            for (int i = 0; i <= 0xff; i++)
            {
                var thindex = i % threadcount;
                threads[thindex].items[(byte)i] = pool.OpenOrCreate((byte)i);
            }
        }
        public static void Queue(byte[] line)
        {
            var thindex = line[0] % threads.Length;
            var thread = threads[thindex];
            threads[thindex].Queue(line);
        }
        public static void WaitToExit()
        {
            WaitWrite();
            for (var i = 0; i < threads.Length; i++)
            {
                threads[i].Stop();
                threads[i] = null;
            }
        }
        public static void WaitWrite()
        {
            while (true)
            {
                int alive = 0;
                for (var i = 0; i < threads.Length; i++)
                {
                    if (threads[i].QueueSize == 0)
                        continue;
                    alive++;
                }
                if (alive == 0)
                    break;
            }
            foreach (var t in threads)
            {
                t.Apply();
            }
        }


        static void ImportAddrGenMap(string type, string[] srcfiles, string outdir)
        {

            var txtdat = System.Text.Encoding.UTF8.GetBytes(type);

            //开启写线程
            LinePool curpool = new LinePool(outdir, 32);

            ////开8个线程写
            //curpool = new FilePool.LinePool(type + "_data", 32);

            FilePool.ThreadWriteMgr.Start(curpool, 16);

            string[] src = new string[8];
            foreach (var f in srcfiles)
            {
                DateTime t0 = DateTime.Now;
                Console.WriteLine("begin " + f + " at:" + t0.ToLongTimeString());
                var lines = System.IO.File.ReadAllLines(f);
                System.Threading.Tasks.Parallel.For(0, 8, (seed) =>
                {
                    for (var l = seed; l < lines.Length; l += 8)
                    {
                        var line = lines[l];
                        {
                            var data = new byte[32];
                            var hex0 = byte.Parse(line.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
                            var hex1 = byte.Parse(line.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
                            var hex2 = byte.Parse(line.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
                            var hex3 = byte.Parse(line.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
                            if (line.Length == 40 + 9)
                            {
                                for (var i = 0; i < 20; i++)
                                {
                                    var d = byte.Parse(line.Substring(9 + i * 2, 2), System.Globalization.NumberStyles.HexNumber);
                                    data[i] = d;
                                }
                            }
                            else if (line.Length == 34 + 9)
                            {
                                var b58 = AddrTools.base58Decode(line.Substring(9));
                                for (var i = 0; i < 20; i++)
                                {
                                    data[i] = b58[i + 1];
                                }
                            }
                            else
                            {
                                //如果遇到不规范的忽略他，只支持两种文本导入格式
                            }
                            //
                            data[20] = hex3;
                            data[21] = hex2;
                            data[22] = hex1;
                            data[23] = hex0;
                            for (var i = 0; i < Math.Min(8, txtdat.Length); i++)
                            {
                                data[24 + i] = txtdat[i];
                            }
                            FilePool.ThreadWriteMgr.Queue(data);
                        }
                    }
                }
                  );

                var time = (DateTime.Now - t0).TotalSeconds;
                Console.WriteLine("end " + f + " " + time);
                FilePool.ThreadWriteMgr.WaitWrite();
            }

            //);
            FilePool.ThreadWriteMgr.WaitToExit();
            //foreach (var f in srcfiles)
            //{
            //    using (var fs = System.IO.File.OpenRead(f))
            //    {
            //        using (var sr = new System.IO.StreamReader(fs))
            //        {
            //            while (true)
            //            {
            //                var line = sr.ReadLine();
            //                if (line == null)
            //                {
            //                    break;
            //                }
            //                var data = new byte[32];
            //                var hex0 = byte.Parse(line.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
            //                var hex1 = byte.Parse(line.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
            //                var hex2 = byte.Parse(line.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
            //                var hex3 = byte.Parse(line.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
            //                for (var i = 0; i < 20; i++)
            //                {
            //                    var d = byte.Parse(line.Substring(9 + i * 2, 2), System.Globalization.NumberStyles.HexNumber);
            //                    data[i] = d;
            //                }
            //                //
            //                data[20] = hex3;
            //                data[21] = hex2;
            //                data[22] = hex1;
            //                data[23] = hex0;
            //                for (var i = 0; i < Math.Min(8, txtdat.Length); i++)
            //                {
            //                    data[24 + i] = txtdat[i];
            //                }
            //                curpool.WriteLine(data);
            //            }
            //        }
            //        Console.WriteLine("finish:" + f);
            //    }

            //}

            curpool.Dispose();
            curpool = null;
        }
    }
}
